import { sRand, getValidIndexes } from './math'
import { TEMP, pushBoxData, matchUnitsToTempBoxRows } from './box'
import type { MagizTypes, StyleTypes, StyleParsed, Temp } from './_imports'
import { Matrix3 } from './_imports'

export { handleMatch }

/** 将 parsed.match 转为纯数据保存到结果 */
function handleMatch(
  result: MagizTypes.DataJSON.ModelData,
  parsedStyle: Pick<StyleParsed.FloorResult, 'match' | 'elevations'>,
  rayLoops: Temp.Ray[][]
) {
  const { match, elevations } = parsedStyle
  match.forEach((params) => {
    // 根据参数旋转平面再进行拟合
    const { ctrlMatch, sandwich, array, along, simplify } = params
    const { newRays, radian } = sRotateLinesAlong(rayLoops.flat(), along)
    const tempBoxRows = matchUnitsToTempBoxRows(array, newRays, sandwich, simplify)
    getValidIndexes(tempBoxRows.length, ctrlMatch).forEach((i) => {
      tempBoxRows[i]!.forEach((data) => {
        elevations.forEach((elevation) => {
          pushBoxData(
            result,
            data.color,
            data.matrix
              .clone()
              .premultiply(TEMP.makeRotationZ(-radian))
              .premultiply(TEMP.makeTranslation(0, 0, elevation))
          )
        })
      })
    })
  })
}

/** 根据along旋转由Plane生成的lines数据，默认按 WIDTH */
function sRotateLinesAlong(rays: Temp.Ray[], along?: StyleTypes.HandleEdge['along']) {
  let radian = 0
  if (typeof along === 'number') {
    radian = along * (Math.PI / 180)
  } else if (along === 'RANDOM') {
    radian = Math.PI * 2 * sRand()
  } else if (along === 'DEPTH') {
    radian = Math.PI / 2
  } else if (along === 'WIDTH') {
    radian = 0
  } else if (along === 'LONGEST') {
    // 找到最长的射线
    const r = rays.reduce((a, b) => (a.direction.length() > b.direction.length() ? a : b))
    radian = r.direction.angle()
  } else if (along === 'SHORTEST') {
    const r = rays.reduce((a, b) => (a.direction.length() < b.direction.length() ? a : b))
    radian = r.direction.angle()
  }

  if (radian) {
    const matrix = new Matrix3().makeRotation(radian)
    rays = rays.map((r) => {
      return {
        direction: r.direction.clone().applyMatrix3(matrix),
        start: r.start.clone().applyMatrix3(matrix),
        end: r.end.clone().applyMatrix3(matrix),
      }
    })
  } else {
    rays = rays.map((r) => {
      return {
        direction: r.direction.clone(),
        start: r.start.clone(),
        end: r.end.clone(),
      }
    })
  }

  return { newRays: rays, radian }
}
